#include "InputManager.h"

InputManager::InputManager(void)
{
	m_directInput = 0;
	m_keyboard = 0;
	m_mouse = 0;
}

InputManager::~InputManager(void)
{
}

bool InputManager::Initialize(HINSTANCE hinstance, HWND hwnd, int screenWidth, int screenHeight)
{	
	HRESULT result;

	// Store the screen size which will be used for positioning the mouse cursor.
	m_screenWidth = screenWidth;
	m_screenHeight = screenHeight;

	// Initialize the location of the mouse on the screen.
	m_mouseX = 0;
	m_mouseY = 0;

	// Initialize the main direct input interface.
	result = DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_directInput, NULL);
	CheckErrorBool(result);

	// Initialize the direct input interface for the keyboard.
	result = m_directInput->CreateDevice(GUID_SysKeyboard, &m_keyboard, NULL);
	CheckErrorBool(result);

	// Set the data format.  In this case since it is a keyboard we can use the predefined data format.
	result = m_keyboard->SetDataFormat(&c_dfDIKeyboard);
	CheckErrorBool(result);

	// Set the cooperative level of the keyboard to not share with other programs.
	result = m_keyboard->SetCooperativeLevel(hwnd, DISCL_BACKGROUND| DISCL_NONEXCLUSIVE);
	CheckErrorBool(result);

	// Now acquire the keyboard.
	result = m_keyboard->Acquire();
	CheckErrorBool(result);

	// Initialize the direct input interface for the mouse.
	result = m_directInput->CreateDevice(GUID_SysMouse, &m_mouse, NULL);
	CheckErrorBool(result);

	// Set the data format for the mouse using the pre-defined mouse data format.
	result = m_mouse->SetDataFormat(&c_dfDIMouse);
	CheckErrorBool(result);

	// Set the cooperative level of the mouse to share with other programs.
	result = m_mouse->SetCooperativeLevel(hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
	CheckErrorBool(result);


	// Acquire the mouse.
	result = m_mouse->Acquire();
	CheckErrorBool(result);

	return true;
}


void InputManager::Shutdown()
{
	// Release the mouse.
	if(m_mouse)
	{
		m_mouse->Unacquire();
		m_mouse->Release();
		m_mouse = 0;
	}

	// Release the keyboard.
	if(m_keyboard)
	{
		m_keyboard->Unacquire();
		m_keyboard->Release();
		m_keyboard = 0;
	}

	// Release the main interface to direct input.
	if(m_directInput)
	{
		m_directInput->Release();
		m_directInput = 0;
	}	
}


bool InputManager::UpdateInputManager()
{
	bool result;

	// Read the current state of the keyboard.
	result = ReadKeyboard();
	if(!result)
	{
		return false;
	}

	// Read the current state of the mouse.
	result = ReadMouse();
	if(!result)
	{
		return false;
	}

	// Process the changes in the mouse and keyboard.
	ProcessInput();

	return true;
}


bool InputManager::ReadKeyboard()
{
	HRESULT result;
	
	memcpy(m_LastkeyboardState, m_keyboardState, sizeof(m_LastkeyboardState)); 	

	// Read the keyboard device.
	result = m_keyboard->GetDeviceState(sizeof(m_keyboardState), (LPVOID)&m_keyboardState);
	if(FAILED(result))
	{
		// If the keyboard lost focus or was not acquired then try to get control back.
		if((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
		{
			m_keyboard->Acquire();
		}
		else
		{
			return false;
		}
	}
		
	return true;
}


bool InputManager::ReadMouse()
{
	HRESULT result;

	m_LastmouseState = m_mouseState;

	// Read the mouse device.
	result = m_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&m_mouseState);
	if(FAILED(result))
	{
		// If the mouse lost focus or was not acquired then try to get control back.
		if((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
		{
			m_mouse->Acquire();
		}
		else
		{
			return false;
		}
	}

	return true;
}



void InputManager::GetRelativeMouseLocation(int &x, int &y)
{
	x = r_mouseX;
	y = r_mouseY;
}

void InputManager::ProcessInput()
{
	r_mouseX = m_mouseState.lX;
	r_mouseY = m_mouseState.lY;
	// Update the location of the mouse cursor based on the change of the mouse location during the frame.
	m_mouseX += m_mouseState.lX;
	m_mouseY += m_mouseState.lY;

	// Ensure the mouse location doesn't exceed the screen width or height.
	if(m_mouseX < 0)  { m_mouseX = 0; }
	if(m_mouseY < 0)  { m_mouseY = 0; }
	
	if(m_mouseX > m_screenWidth)  { m_mouseX = m_screenWidth; }
	if(m_mouseY > m_screenHeight) { m_mouseY = m_screenHeight; }
	
	return;
}

	bool InputManager::isMouseButtonPressed(unsigned char mb)
	{		
		if(m_mouseState.rgbButtons[mb] & 0x80)
		{
			return true;
		}
		return false;
	}

	bool InputManager::isMouseButtonRelease(unsigned char mb)
	{
		return !isMouseButtonPressed(mb);
	}
	bool InputManager::isMouseButtonPressing(unsigned char mb)
	{
		if(m_mouseState.rgbButtons[mb] & 0x80 && m_mouseState.rgbButtons[mb] != m_LastmouseState.rgbButtons[mb])
		{
			return true;
		}
		return false;
	}

	bool InputManager::isMouseButtonReleasing(unsigned char mb)
	{
		if( (m_mouseState.rgbButtons[mb] & 0x80) != 1 && m_mouseState.rgbButtons[mb] != m_LastmouseState.rgbButtons[mb])
		{
			return true;
		}
		return false;
	}


bool InputManager::isKeyReleasing(unsigned char key)
{
	if( (m_keyboardState[key] & 0x80 ) != 1 && m_keyboardState[key] != m_LastkeyboardState[key])
	{
		return true;
	}
	return false;
}


bool InputManager::isKeyPressing(unsigned char key)
{
	if(m_keyboardState[key] & 0x80 && m_keyboardState[key] != m_LastkeyboardState[key])
	{
		return true;
	}
	return false;
}

bool InputManager::isKeyRelease(unsigned char key)
{
	return !isKeyPressed(key);
}

bool InputManager::isKeyPressed(unsigned char key)
{
	// Do a bitwise and on the keyboard state to check if the escape key is currently being pressed.
	if(m_keyboardState[key] & 0x80)
	{
		return true;
	}
	return false;
}

void InputManager::GetMouseLocation(int& mouseX, int& mouseY)
{	
	mouseX = m_mouseX;
	mouseY = m_mouseY;
	return;	
}



